package com.maimao.search.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maimao.core.constant.Constants;
import com.maimao.core.model.resp.Result;
import com.maimao.core.utils.MapUtils;
import com.maimao.model.goods.Goods;
import com.maimao.model.goods.GoodsDetail;
import com.maimao.model.goods.GoodsSku;
import com.maimao.model.goods.SpecDetails;
import com.maimao.model.goods.enums.FormType;
import com.maimao.model.goods.vo.GoodsInfo;
import com.maimao.search.client.BrandClient;
import com.maimao.search.client.CateClient;
import com.maimao.search.client.GoodsClient;
import com.maimao.search.client.SpecDetailClient;
import com.maimao.search.model.goods.EsGoods;
import com.maimao.search.utils.EsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author MaoLin Wang
 * @date 2020/12/27 2:39 下午
 */
@Service
@Slf4j
public class DocService {
    private Logger logger = LoggerFactory.getLogger(DocService.class);
    @Value("${maimao.es.goods.index}")
    private String index;
    @Value("${maimao.es.goods.type}")
    private String type;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private EsUtil esUtil;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private CateClient cateClient;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private SpecDetailClient specDetailClient;


    public void createGoodsDoc() {
        int size = 5;
        int page = 1;
        int totalPages = 0;
        do {
            Result<PageInfo<GoodsInfo>> goodsInfoResult = goodsClient.goodsInfoPage(page++, size);
            if (goodsInfoResult != null && goodsInfoResult.getData() != null) {
                PageInfo<GoodsInfo> pageInfo = goodsInfoResult.getData();
                List<GoodsInfo> goodsInfo = pageInfo.getList();
                totalPages = pageInfo.getPages();
                log.info("total page:{},cur page:{}", pageInfo.getPages(), pageInfo.getPageNum());
                List<EsGoods> esGoods = goodsInfo2EsGoods(goodsInfo);
                if (esGoods != null && esGoods.size() > 0) {
                    esGoods.forEach(goods -> {
                        createDoc(index, goods.getId(), JSON.toJSONString(goods), type);
                    });
                }
            }

        } while (totalPages > 0 && page <= totalPages);

    }


    public boolean updateDoc(String index, String id, String jsonSource, String type) {
        Assert.notNull(id, "update es index :{},id cant not be null ", index);
        UpdateRequest updateRequest = new UpdateRequest(index, type, id);
        updateRequest.doc(jsonSource, XContentType.JSON);
        try {
            UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            logger.error("update index {} error, json content:{},id is {}", index, jsonSource, id);
            e.printStackTrace();
            return false;
        }
    }

    public void createDoc(String index, Long id, String jsonSource, String type) {
        IndexRequest indexRequest = new IndexRequest(index, type);
        indexRequest.id(id == null ? null : String.valueOf(id));
        indexRequest.source(jsonSource, XContentType.JSON);
        IndexResponse indexResponse = null;
        try {
            indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            if (index != null) {
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    logger.info("新增文档成功,index:{},id:{}", indexRequest, id);
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    logger.info("覆盖文档成功,index:{},id:{}", indexRequest, id);
                }
            }
        } catch (IOException e) {
            logger.error("新增文档失败{}", e.getMessage());
            e.printStackTrace();
        }

    }

    public List<EsGoods> goodsInfo2EsGoods(List<GoodsInfo> goodsInfoList) {
        if (goodsInfoList != null && goodsInfoList.size() > 0) {
            List<EsGoods> esGoodsList = new ArrayList<>(goodsInfoList.size());

            EsGoods esGoods = null;
            for (GoodsInfo goodsInfo : goodsInfoList) {
                esGoods = new EsGoods();
                Goods goods = goodsInfo.getGoods();
                GoodsDetail goodsDetail = goodsInfo.getGoodsDetail();
                List<GoodsSku> skus = goodsInfo.getSkus();

                List<BigDecimal> priceList = new ArrayList<>();
                List<Map<String, Object>> skuList = Lists.newArrayList();
                if (skus != null && skus.size() > 0) {
                    skuList = new ArrayList<>(skus.size());
                    Map<String, Object> skuMap = null;
                    for (GoodsSku sku : skus) {
                        priceList.add(sku.getPrice().setScale(2));
                        skuMap = new HashMap<>(MapUtils.initCapacity(4));
                        skuMap.put("id", sku.getId());
                        skuMap.put("name", sku.getName());
                        skuMap.put("price", sku.getPrice());
                        skuMap.put("specIndexes", sku.getSpecIndexes());
                        List<String> pictureList = JSON.parseObject(sku.getPictures(), List.class);
                        String pic = "";
                        if (pictureList != null && pictureList.size() > 0) {
                            Integer showIndex = sku.getShowIndex();
                            if (showIndex == null || StringUtils.isEmpty(pictureList.get(showIndex))) {
                                pic = pictureList.get(0);
                            } else {
                                pic = pictureList.get(showIndex);
                            }
                        }
                        skuMap.put("picture", pic);
                        skuList.add(skuMap);
                    }
                }
                esGoods.setPriceList(priceList);
                esGoods.setSearchParams(buildSearchParams(skus, goodsDetail, goods.getCid3()));
                esGoods.setGoodsSkus(JSON.toJSONString(skuList));

                Map<String, Object> suggestions = new HashMap<>();
                String[] keywordsArray = goods.getKeywords().trim().split(Constants.BLANK);
                if (keywordsArray != null && keywordsArray.length > 0) {
                    suggestions.put("input", keywordsArray);
                    suggestions.put("weight", 10);
                }
                esGoods.setSuggestions(suggestions);

                esGoods.setKey(getEsGoodsKey(goods));

                esGoods.setSellCount(goods.getSellCount());
                esGoods.setId(goods.getId());
                esGoods.setBrandId(goods.getBrandId());
                esGoods.setCid1(goods.getCid1());
                esGoods.setCid2(goods.getCid2());
                esGoods.setCid3(goods.getCid3());
                esGoods.setCreateTime(goods.getCreateTime());
                esGoods.setShopId(goods.getShopId());
                esGoods.setShopName(goods.getShopName());
                esGoods.setSubName(goods.getSubName());

                esGoodsList.add(esGoods);
            }
            return esGoodsList;
        }
        return null;
    }

    /**
     * 构造可搜索规格参数
     */
    private Map<String, Object> buildSearchParams(List<GoodsSku> skus, GoodsDetail goodsDetail, Integer cid) {
        Result<List<SpecDetails>> specRes = specDetailClient.findSearchSpecByCid(cid);
        if (specRes == null || specRes.getData() == null) {
            return Maps.newHashMap();
        }
        List<SpecDetails> specDetailsList = specRes.getData();

        //通用规格
        Map<String, Object> commonSpec = JSON.parseObject(goodsDetail.getCommonParam(), Map.class);
        //销售规格(sku规格)
        Map<String, List<Object>> sellParam = JSON.parseObject(goodsDetail.getSkuParam(), Map.class);

        Map<String, Object> searchParams = Maps.newHashMap();
        if (specDetailsList.size() > 0) {
            searchParams = new HashMap<>(MapUtils.initCapacity(specDetailsList.size()));
            for (SpecDetails specDetails : specDetailsList) {
                if (specDetails.getCommon().equals(Constants.ONE)) {
                    //通用规格
                    Object value = commonSpec.get(specDetails.getId().toString());
                    if (specDetails.getNumberic()) {
                        //是数字类型的话 需要根据区间取值
                        value = getNumberValue(value, specDetails.getSearchOptional(), specDetails.getUnit());
                    }
                    searchParams.put(specDetails.getName(), value);

                } else {
                    List<Object> sellParams = sellParam.get(specDetails.getId().toString());
                    if (ObjectUtil.isNotEmpty(sellParams) && specDetails.getFormType().equals(FormType.NUMBER.getName())) {
                        List<String> res = sellParams.stream().map(Object::toString).collect(Collectors.toList());
                        searchParams.put(specDetails.getName(), res);

                    } else {
                        searchParams.put(specDetails.getName(), sellParams);

                    }
                }
            }
        }
        return searchParams;
    }

    private String getNumberValue(Object value, String searchOptional, String unit) {
        double targetValue = NumberUtils.toDouble(value.toString());
        String res = "其他";
        String[] options = searchOptional.split(Constants.COMMA);
        if (options != null && options.length > 0) {
            for (String option : options) {
                if (option.indexOf(Constants.MIDDLE_LINE) != -1) {
                    String[] range = option.split(Constants.MIDDLE_LINE_STR);
                    double from = NumberUtils.toDouble(range[0]);
                    double to = Double.MAX_VALUE;
                    if (range.length == 2) {
                        to = NumberUtils.toDouble(range[1]);
                    }
                    if (targetValue >= from && targetValue <= to) {
                        if (range.length == 1) {
                            res = from + unit + "以上";
                        } else if (from == 0) {
                            res = to + unit + "以下";
                        } else {
                            res = option + unit;
                        }
                        break;
                    }
                } else {
                    if (option.equals(value.toString())) {
                        return option;
                    }
                }
            }
        }
        return res;

    }

    private String getEsGoodsKey(Goods goods) {
        Result<List<String>> cateRes = cateClient.selectNamesByIds(Lists.newArrayList(goods.getCid1(), goods.getCid2(), goods.getCid3()));
        String key = goods.getName().trim() + Constants.BLANK + goods.getKeywords().trim() + Constants.BLANK;
        if (cateRes != null && cateRes.getData() != null) {
            List<String> cateNames = cateRes.getData();
            if (cateNames != null && cateNames.size() > 0) {
                key += StringUtils.join(cateNames, Constants.BLANK);
            }
        }

        Result<String> brandRes = brandClient.selectNameById(goods.getBrandId());
        if (brandRes != null && brandRes.getData() != null) {
            String brandName = brandRes.getData();
            if (!StringUtils.isEmpty(brandName)) {
                key += brandName;
            }
        }
        return key;
    }


}
